package com.app.mvc.datasource; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.lang.reflect.Method; /** * 动态数据源Advisor * Created by jimin on 16/03/22. */ @Slf4j @Component @Aspect @Order(AspectOrder.ROUTING_DATA_SOURCE) public class RoutingDataSourceAdvisor { @Pointcut("execution(@com.app.mvc.datasource.RoutingDataSource * com.app.mvc..*Service+.*(..))") private void routingDataSource() { } @Around("routingDataSource()") public Object routing(ProceedingJoinPoint joinPoint) throws Exception { Class<?> clazz = joinPoint.getTarget().getClass(); String className = clazz.getName(); Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); String methodName = method.getName(); Object[] arguments = joinPoint.getArgs(); String key; RoutingDataSource routingDataSource = method.getAnnotation(RoutingDataSource.class); key = routingDataSource.value().getKey(); log.info("Routing to datasource({}) in {}.{}, args={}", key, className, methodName, arguments); Object result = null; DataSourceKeyHolder.set(key); try { checkIfCompatible(clazz, method); result = joinPoint.proceed(arguments); } catch (Throwable e) { log.error("Error occurred during datasource(key=" + key + ") routing, ", e); } finally { DataSourceKeyHolder.clear(); } return result; } private void checkIfCompatible(Class<?> clazz, Method method) { if (DataSourceKeyHolder.isNestedCall()) { Transactional transactional = method.getAnnotation(Transactional.class); if (transactional == null) { transactional = clazz.getAnnotation(Transactional.class); } if (transactional != null) { if (transactional.propagation() != Propagation.REQUIRES_NEW) { throw new RuntimeException("@RoutingDataSource方法嵌套调用时, 如果内部方法具有@Transactional注解, 必须定义为propagation = REQUIRES_NEW"); } } } } }